﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using FarseerPhysics.Collision.Shapes;
using FarseerPhysics.Common;
using FarseerPhysics.Dynamics;
using FarseerPhysics.Dynamics.Joints;
using FarseerPhysics.Factories;


namespace MountainORocks
{
    public enum ShapeType
    {
        Rect, Circle 
    };

    public enum ShapeM
    {
        Stone, Wood , Glass, Crystal
    };

    public class GameShape
    {
        private Color color;
        public Body body;
        public ShapeType shapeType;
        public ShapeM shapMat;
        public Vector2 origin;
        public Rectangle position;
        public static Texture2D SquareWoodTexture, CircleWoodTexture, SquareRockTexture, CircleRockTexture, SquareGlassTexture, CircleGlassTexture, CrystalTexture;
       
        // whether the shape can disappear from the game
        public Boolean canDisappear;
        double timeForCrystal = 10.0;
        private static Color nonDisappearingColor = Color.Red;
        private static List<Color> disapperingColors = null;
        private static Random random = null;
        private Texture2D myTexture;
        float bodyRot = 0;
        static Game1 myGame;
        bool removeMe = false;


        public static void loadTexture(Texture2D squareW, Texture2D circleW, Texture2D squareR, Texture2D circleR, Texture2D squareG, Texture2D circleG,Texture2D cryText, Game1 thisGame)
        {
            SquareWoodTexture = squareW;
            CircleWoodTexture = circleW;
            SquareRockTexture = squareR;
            CircleRockTexture = circleR;
            SquareGlassTexture = squareG;
            CircleGlassTexture = circleG;
            myGame = thisGame;
            CrystalTexture = cryText;


        }

        public GameShape(World world, ShapeType shapeType, ShapeM shapM, Rectangle Nposition)
            : this(world, shapeType, shapM, Nposition, false)
        {
        }

        public int getPower()
        {
            return (int)this.body.Mass*2;
        }

        public bool getRemoveMe()
        {
            return removeMe;
        }

        /// <summary>
        /// used to load shape from a data file
        /// </summary>
        /// <param name="world"></param>
        /// <param name="shapeType"></param>
        /// <param name="posRect"></param>
        /// <param name="color"></param>
        /// <param name="isStatic"></param>
        /// <param name="canDisappear"></param>
        public GameShape(World world, ShapeType shapeType,ShapeM shapM ,  Rectangle posRect, Color color, bool isStatic,float mass)
        {
            createNewShape(world, shapeType,shapM, posRect, color, isStatic, mass);
        }

        /// <summary>
        /// used to create new shapes
        /// </summary>
        /// <param name="world"></param>
        /// <param name="shapeType"></param>
        /// <param name="Nposition"></param>
        /// <param name="isStatic"></param>
        public GameShape(World world, ShapeType shapeType, ShapeM shapM, Rectangle posRect, bool isStatic)
        {
            // if still didn't init the disappearing colors so init them
            if (GameShape.disapperingColors == null) initDisappearingColor();
            // if still didn't create the random create it
            if (random == null) initRandom();

            Color newColor = color = disapperingColors[random.Next(disapperingColors.Count)];
            // default (shoud change? )
            float mass = 5000f;
            // by default all shapes can disappear

            createNewShape(world, shapeType, shapM, posRect, newColor, isStatic, mass);

        }

        private void initRandom()
        {
            GameShape.random = new Random();
        }

        private void initDisappearingColor()
        {
            disapperingColors = new List<Color>();
            disapperingColors.Add(Color.Blue);
            disapperingColors.Add(Color.Gray);
            disapperingColors.Add(Color.LightGray);
        }

        
        public Color Color
        {
            get
            {
                if (canDisappear) return this.color;
                else return GameShape.nonDisappearingColor;
            }
        }
        
     /*   public Vector2 getOrigin
        {
            get
            {
                switch (shapeType)
                {
                    case ShapeType.Rect:
                        {
                            int x = position.Width/2;
                            int y = position.Height/2;
                            return new Vector2(0, 0);
                        }
                    case ShapeType.Circle:
                        {
                            int x = position.Width/2;
                            int y = position.Height/2;
                            return new Vector2(x, y);

                        }
                }
                return Vector2.Zero;
            }
        }*/

        public int Height
        {
            get
            {
                return position.Height;
            }
        }

        public int Width
        {
            get
            {
                return position.Width;
            }
        }

        public void draw(SpriteBatch spriteBatch)
        {

           
            float d = (float)body.Friction /10;
            if (Math.Abs(body.LinearVelocity.X) < 0.3f)
                d = 0f;
            if (body.LinearVelocity.Y < 0.2f) //0.2 is good
                d = 0f;

            bodyRot += (body.LinearVelocity.X + body.LinearVelocity.Y) * (float)Math.Sqrt(d)/50;

            if (shapeType == ShapeType.Rect) spriteBatch.Draw(myTexture, new Rectangle((int)body.Position.X, (int)body.Position.Y, Width, Height), null, Color.White, body.Rotation, new Vector2(0, 0), SpriteEffects.None, 0f);
            else spriteBatch.Draw(myTexture, new Rectangle((int)body.Position.X, (int)body.Position.Y, Width, Height), null, Color.White, body.Rotation, new Vector2(myTexture.Width / 2, myTexture.Height / 2), SpriteEffects.None, 0f);


        }


        /// <summary>
        /// used in all the contructors
        /// </summary>
        /// <param name="world"></param>
        /// <param name="shapeType"></param>
        /// <param name="posRect"></param>
        /// <param name="color"></param>
        /// <param name="isStatic"></param>
        /// <param name="canDisappear"></param>
        /// <param name="mass"></param>
        private void createNewShape(World world, ShapeType shapeType, ShapeM shapM, Rectangle posRect, Color color, bool isStatic, float mass)
        {
            this.shapeType = shapeType;
            this.shapMat = shapM;

            // this.color = disapperingColors[random.Next(disapperingColors.Count - 1)];
            this.color = color;

            Vertices vertices = new Vertices();

            position = posRect;

            this.body = new Body(world, vertices);
            if (isStatic) this.body.BodyType = BodyType.Static;
            else this.body.BodyType = BodyType.Dynamic;
            switch (shapeType)
            {
                case ShapeType.Rect:
                    {
                        

                        
                        vertices = PolygonTools.CreateRectangle(this.position.Width / 2, this.position.Height / 2,
                            new Vector2(this.position.Width / 2, this.position.Height / 2), 0.0f);
                        this.body.CreateFixture(new PolygonShape(vertices, 1));
                        this.body.Position = new Vector2(this.position.X, this.position.Y);
                        this.body.Rotation = 0.0f;
                        this.body.Friction = 0.3f;
                        this.body.Mass = this.position.Width * this.position.Height;
                        this.body.LocalCenter = new Vector2(position.Width / 2, position.Height / 2);

                        if (shapM == ShapeM.Stone)
                        {
                            myTexture = SquareRockTexture;
                            this.body.Mass = this.body.Mass * 2;
                            this.body.OnCollision += new OnCollisionEventHandler(body_OnCollision);
                            this.body.UserData = (object)0;
                        }
                        if (shapM == ShapeM.Wood)
                        {
                            myTexture = SquareWoodTexture;
                            this.body.OnCollision += new OnCollisionEventHandler(body_OnCollision);
                            canDisappear = true;
                            this.body.UserData = (object)0;
                        }
                        if (shapM == ShapeM.Crystal)
                        {
                            myTexture = CrystalTexture;
                            canDisappear = true;
                            this.body.OnCollision+=new OnCollisionEventHandler(body_OnCollision_Crystal);
                            this.body.Mass = this.body.Mass / 70;
                            this.body.UserData = (object)1;

                        }
                        if (shapM == ShapeM.Glass)
                        {
                            myTexture = SquareGlassTexture;
                            canDisappear = true;
                            this.body.OnCollision += new OnCollisionEventHandler(body_OnCollision);
                            this.body.Mass = this.body.Mass / 15;
                            this.body.UserData = (object)0;
                            
            
                        }
                        this.body.UserData = (object)shapM;
                        break;
                    }

                case ShapeType.Circle:
                    {
                        


                        //FixtureFactory.AttachEllipse(this.position.Width / 2, this.position.Height / 2, 0, 1, this.body);
                        CircleShape circleShape = new CircleShape(((float)(this.position.Width)) / 2.0f, 4f);
                        
                        this.body.CreateFixture(circleShape);
                        this.body.Position = new Vector2(this.position.X, this.position.Y);
                        this.body.Friction = 0.3f;
                        this.body.Rotation = 0.0f;
                       //this.body.OnCollision += new OnCollisionEventHandler(body_OnCollision);
            
                       // this.body.LinearDamping = 0.1f;
                        //this.body.LocalCenter = new Vector2(((float)(this.position.Width)) / 2.0f, ((float)(this.position.Width)) / 2.0f);
                        this.body.Mass = (float)(Math.Pow((this.position.Width/2),2)* Math.PI);

                        if (shapM == ShapeM.Stone)
                        {
                            
                            myTexture = CircleRockTexture;
                            this.body.Mass = this.body.Mass *2;
                            this.body.OnCollision += new OnCollisionEventHandler(body_OnCollision);
                            this.body.UserData = (object)0;
                        }
                        if (shapM == ShapeM.Wood)
                        {
                            myTexture = CircleWoodTexture;
                            this.body.OnCollision += new OnCollisionEventHandler(body_OnCollision);
                            canDisappear = true;
                            this.body.UserData = (object)0;
                        }
                        if (shapM == ShapeM.Glass)
                        {
                            myTexture = CircleGlassTexture;
                            canDisappear = true;
                            this.body.OnCollision += new OnCollisionEventHandler(body_OnCollision);
                            this.body.Mass = this.body.Mass / 15;
                            this.body.UserData = (object)0;
            
                        }

                        this.body.UserData = (object)shapM;

                        break;
                    }
                    
            }

            // create the body 

            //this.body.Mass = mass;
            // default (shoud change? )           
           // body.Mass = 5000f;

            // by default all shapes can disappear
            
        }

        bool body_OnCollision_Crystal(Fixture fixtureA, Fixture fixtureB, FarseerPhysics.Dynamics.Contacts.Contact contact)
        {
            if ((fixtureA.Body == this.body) && (fixtureB.Body == myGame.charBody))
            {
                myGame.RemoveShape(fixtureA.Body,false);

            }
            if ((fixtureB.Body == this.body) && (fixtureA.Body == myGame.charBody))
            {
                    myGame.RemoveShape(fixtureB.Body,false);

            }
            return true;

        }



        bool body_OnCollision(Fixture fixtureA, Fixture fixtureB, FarseerPhysics.Dynamics.Contacts.Contact contact)
        {
            if (fixtureA.Body.UserData != null && (ShapeM)fixtureA.Body.UserData == ShapeM.Glass)
            {
                if ((Math.Abs(fixtureA.Body.LinearVelocity.Y) > 100) || (Math.Abs(fixtureA.Body.LinearVelocity.X) > 100) || (Math.Abs(fixtureB.Body.LinearVelocity.Y) > 100) || (Math.Abs(fixtureB.Body.LinearVelocity.X) > 100))
                    myGame.RemoveShape(fixtureA.Body,false);

            }
            if (fixtureB.Body.UserData!=null && (ShapeM)fixtureB.Body.UserData == ShapeM.Glass)
            {
                if ((Math.Abs(fixtureA.Body.LinearVelocity.Y) > 100) || (Math.Abs(fixtureA.Body.LinearVelocity.X) > 100) || (Math.Abs(fixtureB.Body.LinearVelocity.Y) > 100) || (Math.Abs(fixtureB.Body.LinearVelocity.X) > 100))
                    myGame.RemoveShape(fixtureB.Body, false);

            }
            return true;

        }


        public void update(GameTime gameTime)
        {
            if (shapMat == ShapeM.Crystal)
            {
                timeForCrystal -= gameTime.ElapsedGameTime.TotalSeconds;
                if (timeForCrystal < 0)
                {
                   // myGame.RemoveShape(this.body);
                    removeMe = true;
                }


            }


        }


        internal void drawSelected(SpriteBatch spriteBatch)
        {
          

            Color tintColor = Color.Cornsilk;
            tintColor.A = 30;

            float d = (float)body.Friction / 10;
            if (Math.Abs(body.LinearVelocity.X) < 0.3f)
                d = 0f;
            if (body.LinearVelocity.Y < 0.2f) //0.2 is good
                d = 0f;

            bodyRot += (body.LinearVelocity.X + body.LinearVelocity.Y) * (float)Math.Sqrt(d) / 50;


            if (shapeType == ShapeType.Rect) spriteBatch.Draw(myTexture, new Rectangle((int)body.Position.X, (int)body.Position.Y, Width, Height), null, tintColor, body.Rotation, new Vector2(0, 0), SpriteEffects.None, 0f);
            else spriteBatch.Draw(myTexture, new Rectangle((int)body.Position.X, (int)body.Position.Y, Width, Height), null, tintColor, body.Rotation, new Vector2(myTexture.Width / 2, myTexture.Height / 2), SpriteEffects.None, 0f);

            

        }
    }
}
